home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / gcc263-src.lha / gcc-2.6.3 / config / fx80 / fx80.c next >
C/C++ Source or Header  |  1994-03-13  |  9KB  |  300 lines

  1. /* Subroutines for insn-output.c for Alliant FX computers.
  2.    Copyright (C) 1989,1991 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20.  
  21. /* Some output-actions in alliant.md need these.  */
  22. #include <stdio.h>
  23. #include "config.h"
  24. #include "rtl.h"
  25. #include "regs.h"
  26. #include "hard-reg-set.h"
  27. #include "real.h"
  28. #include "insn-config.h"
  29. #include "conditions.h"
  30. #include "insn-flags.h"
  31. #include "output.h"
  32. #include "insn-attr.h"
  33.  
  34. /* Index into this array by (register number >> 3) to find the
  35.    smallest class which contains that register.  */
  36. enum reg_class regno_reg_class[]
  37.   = { DATA_REGS, ADDR_REGS, FP_REGS };
  38.  
  39. static rtx find_addr_reg ();
  40.  
  41. char *
  42. output_btst (operands, countop, dataop, insn, signpos)
  43.      rtx *operands;
  44.      rtx countop, dataop;
  45.      rtx insn;
  46.      int signpos;
  47. {
  48.   operands[0] = countop;
  49.   operands[1] = dataop;
  50.  
  51.   if (GET_CODE (countop) == CONST_INT)
  52.     {
  53.       register int count = INTVAL (countop);
  54.       /* If COUNT is bigger than size of storage unit in use,
  55.      advance to the containing unit of same size.  */
  56.       if (count > signpos)
  57.     {
  58.       int offset = (count & ~signpos) / 8;
  59.       count = count & signpos;
  60.       operands[1] = dataop = adj_offsettable_operand (dataop, offset);
  61.     }
  62.       if (count == signpos)
  63.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  64.       else
  65.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  66.  
  67.       /* These three statements used to use next_insns_test_no...
  68.      but it appears that this should do the same job.  */
  69.       if (count == 31
  70.       && next_insn_tests_no_inequality (insn))
  71.     return "tst%.l %1";
  72.       if (count == 15
  73.       && next_insn_tests_no_inequality (insn))
  74.     return "tst%.w %1";
  75.       if (count == 7
  76.       && next_insn_tests_no_inequality (insn))
  77.     return "tst%.b %1";
  78.  
  79.       cc_status.flags = CC_NOT_NEGATIVE;
  80.     }
  81.   return "btst %0,%1";
  82. }
  83.  
  84. /* Return the best assembler insn template
  85.    for moving operands[1] into operands[0] as a fullword.  */
  86.  
  87. static char *
  88. singlemove_string (operands)
  89.      rtx *operands;
  90. {
  91.   if (operands[1] != const0_rtx)
  92.     return "mov%.l %1,%0";
  93.   if (! ADDRESS_REG_P (operands[0]))
  94.     return "clr%.l %0";
  95.   return "sub%.l %0,%0";
  96. }
  97.  
  98. /* Output assembler code to perform a doubleword move insn
  99.    with operands OPERANDS.  */
  100.  
  101. char *
  102. output_move_double (operands)
  103.      rtx *operands;
  104. {
  105.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  106.   rtx latehalf[2];
  107.   rtx addreg0 = 0, addreg1 = 0;
  108.  
  109.   /* First classify both operands.  */
  110.  
  111.   if (REG_P (operands[0]))
  112.     optype0 = REGOP;
  113.   else if (offsettable_memref_p (operands[0]))
  114.     optype0 = OFFSOP;
  115.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  116.     optype0 = POPOP;
  117.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  118.     optype0 = PUSHOP;
  119.   else if (GET_CODE (operands[0]) == MEM)
  120.     optype0 = MEMOP;
  121.   else
  122.     optype0 = RNDOP;
  123.  
  124.   if (REG_P (operands[1]))
  125.     optype1 = REGOP;
  126.   else if (CONSTANT_P (operands[1]))
  127.     optype1 = CNSTOP;
  128.   else if (offsettable_memref_p (operands[1]))
  129.     optype1 = OFFSOP;
  130.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  131.     optype1 = POPOP;
  132.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  133.     optype1 = PUSHOP;
  134.   else if (GET_CODE (operands[1]) == MEM)
  135.     optype1 = MEMOP;
  136.   else
  137.     optype1 = RNDOP;
  138.  
  139.   /* Check for the cases that the operand constraints are not
  140.      supposed to allow to happen.  Abort if we get one,
  141.      because generating code for these cases is painful.  */
  142.  
  143.   if (optype0 == RNDOP || optype1 == RNDOP)
  144.     abort ();
  145.  
  146.   /* If one operand is decrementing and one is incrementing
  147.      decrement the former register explicitly
  148.      and change that operand into ordinary indexing.  */
  149.  
  150.   if (optype0 == PUSHOP && optype1 == POPOP)
  151.     {
  152.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  153.       output_asm_insn ("subq%.l %#8,%0", operands);
  154.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  155.       optype0 = OFFSOP;
  156.     }
  157.   if (optype0 == POPOP && optype1 == PUSHOP)
  158.     {
  159.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  160.       output_asm_insn ("subq%.l %#8,%1", operands);
  161.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  162.       optype1 = OFFSOP;
  163.     }
  164.  
  165.   /* If an operand is an unoffsettable memory ref, find a register
  166.      we can increment temporarily to make it refer to the second word.  */
  167.  
  168.   if (optype0 == MEMOP)
  169.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  170.  
  171.   if (optype1 == MEMOP)
  172.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  173.  
  174.   /* Ok, we can do one word at a time.
  175.      Normally we do the low-numbered word first,
  176.      but if either operand is autodecrementing then we
  177.      do the high-numbered word first.
  178.  
  179.      In either case, set up in LATEHALF the operands to use
  180.      for the high-numbered word and in some cases alter the
  181.      operands in OPERANDS to be suitable for the low-numbered word.  */
  182.  
  183.   if (optype0 == REGOP)
  184.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  185.   else if (optype0 == OFFSOP)
  186.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  187.   else
  188.     latehalf[0] = operands[0];
  189.  
  190.   if (optype1 == REGOP)
  191.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  192.   else if (optype1 == OFFSOP)
  193.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  194.   else if (optype1 == CNSTOP)
  195.     {
  196.       if (GET_CODE (operands[1]) == CONST_DOUBLE)
  197.     split_double (operands[1], &operands[1], &latehalf[1]);
  198.       else if (CONSTANT_P (operands[1]))
  199.     {
  200.       latehalf[1] = operands[1];
  201.       operands[1] = const0_rtx;
  202.     }
  203.     }
  204.   else
  205.     latehalf[1] = operands[1];
  206.  
  207.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  208.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  209.      for the low word as well, to compensate for the first decrement of sp.  */
  210.   if (optype0 == PUSHOP
  211.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  212.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  213.     operands[1] = latehalf[1];
  214.  
  215.   /* If one or both operands autodecrementing,
  216.      do the two words, high-numbered first.  */
  217.  
  218.   /* Likewise,  the first move would clobber the source of the second one,
  219.      do them in the other order.  This happens only for registers;
  220.      such overlap can't happen in memory unless the user explicitly
  221.      sets it up, and that is an undefined circumstance.  */
  222.  
  223.   if (optype0 == PUSHOP || optype1 == PUSHOP
  224.       || (optype0 == REGOP && optype1 == REGOP
  225.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  226.     {
  227.       /* Make any unoffsettable addresses point at high-numbered word.  */
  228.       if (addreg0)
  229.     output_asm_insn ("addql %#4,%0", &addreg0);
  230.       if (addreg1)
  231.     output_asm_insn ("addql %#4,%0", &addreg1);
  232.  
  233.       /* Do that word.  */
  234.       output_asm_insn (singlemove_string (latehalf), latehalf);
  235.  
  236.       /* Undo the adds we just did.  */
  237.       if (addreg0)
  238.     output_asm_insn ("subql %#4,%0", &addreg0);
  239.       if (addreg1)
  240.     output_asm_insn ("subql %#4,%0", &addreg1);
  241.  
  242.       /* Do low-numbered word.  */
  243.       return singlemove_string (operands);
  244.     }
  245.  
  246.   /* Normal case: do the two words, low-numbered first.  */
  247.  
  248.   output_asm_insn (singlemove_string (operands), operands);
  249.  
  250.   /* Make any unoffsettable addresses point at high-numbered word.  */
  251.   if (addreg0)
  252.     output_asm_insn ("addql %#4,%0", &addreg0);
  253.   if (addreg1)
  254.     output_asm_insn ("addql %#4,%0", &addreg1);
  255.  
  256.   /* Do that word.  */
  257.   output_asm_insn (singlemove_string (latehalf), latehalf);
  258.  
  259.   /* Undo the adds we just did.  */
  260.   if (addreg0)
  261.     output_asm_insn ("subql %#4,%0", &addreg0);
  262.   if (addreg1)
  263.     output_asm_insn ("subql %#4,%0", &addreg1);
  264.  
  265.   return "";
  266. }
  267.  
  268. /* Return a REG that occurs in ADDR with coefficient 1.
  269.    ADDR can be effectively incremented by incrementing REG.  */
  270.  
  271. static rtx
  272. find_addr_reg (addr)
  273.      rtx addr;
  274. {
  275.   while (GET_CODE (addr) == PLUS)
  276.     {
  277.       if (GET_CODE (XEXP (addr, 0)) == REG)
  278.     addr = XEXP (addr, 0);
  279.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  280.     addr = XEXP (addr, 1);
  281.       else if (CONSTANT_P (XEXP (addr, 0)))
  282.     addr = XEXP (addr, 1);
  283.       else if (CONSTANT_P (XEXP (addr, 1)))
  284.     addr = XEXP (addr, 0);
  285.       else
  286.     abort ();
  287.     }
  288.   if (GET_CODE (addr) == REG)
  289.     return addr;
  290.   abort ();
  291. }
  292.  
  293. int
  294. standard_SunFPA_constant_p (x)
  295.      rtx x;
  296. {
  297.   return( 0 );
  298. }
  299.  
  300.